Skip to content

fix(storage): validate page refs on update_page to block dangling graph links#468

Open
RealDiligent wants to merge 3 commits into
vouchdev:testfrom
RealDiligent:fix/critical-issue-update-page-refs
Open

fix(storage): validate page refs on update_page to block dangling graph links#468
RealDiligent wants to merge 3 commits into
vouchdev:testfrom
RealDiligent:fix/critical-issue-update-page-refs

Conversation

@RealDiligent

Copy link
Copy Markdown
Contributor

Summary

Root cause: update_page() — used when approving vault-edit proposals for existing pages — did not re-validate graph references before persisting. put_page() and update_claim() already enforce ref integrity, but page updates could land with dangling claims / entities / sources links if a referenced artifact was deleted between propose and approve.

Fix: Extract _validate_page_refs() (mirroring _validate_claim_refs) and call it from both put_page() and update_page(). update_page() also round-trips through Page.model_validate() like update_claim() does for model invariants.

Impact: Vault-sync and other page-edit approvals can no longer silently corrupt the KB graph. Operators get a clear ValueError instead of durable dangling references that vouch lint would only catch later.

Reproduction

# 1. Page exists citing claim c1
# 2. Vault-sync proposes an edit (still valid at propose time)
# 3. Claim c1 deleted before approve
approve(store, proposal_id, approved_by="reviewer")
# main: succeeds → page cites missing claim
# this branch: ValueError: page p1 references unknown claim c1

Regression tests: test_update_page_rejects_dangling_claim_ref, test_approve_page_update_rejects_stale_claim_ref.

Risk / tradeoffs

  • Stale vault-edit proposals (referenced artifacts deleted between propose and approve) now fail at write time — same behavior as claim/relation paths. Reviewer rejects and re-proposes.

Test plan

  • test_update_page_rejects_dangling_claim_ref
  • test_approve_page_update_rejects_stale_claim_ref
  • tests/test_storage.py + tests/test_vault_sync.py pass

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@plind-junior, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 57 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3d4cd201-e482-4c5d-9aa5-bdff022786bd

📥 Commits

Reviewing files that changed from the base of the PR and between 4de2b66 and 0219eb9.

📒 Files selected for processing (4)
  • src/vouch/proposals.py
  • src/vouch/storage.py
  • tests/test_delete.py
  • tests/test_storage.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added storage kb storage, migrations, schemas, and proposals tests tests and fixtures size: S 50-199 changed non-doc lines labels Jul 13, 2026
update_page lacked the graph-integrity ref checks that put_page and
update_claim already enforce. Vault-edit approvals could land pages
citing claims deleted between propose and approve.

Co-authored-by: Cursor <cursoragent@cursor.com>
@RealDiligent

Copy link
Copy Markdown
Contributor Author

Follow-up commit: \�pprove()\ now calls _payload_block_reason()\ before writing, so single-approve paths (web console, MCP) get a clean \ProposalError\ instead of a raw \ValueError\ when refs go stale between propose and approve. Batch CLI already had this via \check_approvable(); this closes the drift. Storage-layer _validate_page_refs()\ in \update_page()\ remains as defense-in-depth (same pattern as \update_claim()).

RealDiligent and others added 2 commits July 13, 2026 19:49
…paths

Batch CLI already calls check_approvable(); web/MCP approve() did not,
so stale vault-edit refs surfaced as ValueError instead of ProposalError.
Defense-in-depth alongside update_page ref validation.

Co-authored-by: Cursor <cursoragent@cursor.com>
approve() now runs _payload_block_reason before delete, so the error
message uses referenced by instead of still referenced by.

Co-authored-by: Cursor <cursoragent@cursor.com>
@plind-junior

Copy link
Copy Markdown
Member

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: S 50-199 changed non-doc lines storage kb storage, migrations, schemas, and proposals tests tests and fixtures

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants